/**
 * @file imageDecoder.h
 * @author SDK_TEAM
 * @brief
 * @version 0.1
 * @date 2022-11-09
 *
 * Copyright:
 * © 2018 北京灵汐科技有限公司 版权所有。
 * 注意：以下内容均为北京灵汐科技有限公司原创，未经本公司允许，不得转载，否则将视为侵权；对于不遵守此声明或者其他违法使用以下内容者，本公司依法保留追究权。
 * © 2018 Lynxi Technologies Co., Ltd. All rights reserved.
 * NOTICE: All information contained here is, and remains the property of Lynxi.
 * This file can not be copied or distributed without the permission of Lynxi
 * Technologies Co., Ltd.
 *
 */
#pragma once

#include <lyn_api.h>
#include <fstream>
#include <string>
#include <thread>
#include "util.hpp"

// 图片解码类
class ImageDecoder {
 public:
  ImageDecoder() {}

  // 根据路径初始化相关信息
  void Init(const std::string &imagePath, bool enableHwDec = true) {
    m_imagePath = imagePath;
    lynImageDecPara_t imgDecParam = {
        .imgUrl = imagePath.c_str(),
        .scale = SCALE_NONE,
        .outputFmt = LYN_PIX_FMT_NV12,
        .align = true,
    };

    // 解码参数
    std::vector<lynScale_t> vecScale = {SCALE_NONE, SCALE_DOWN_2X,
                                        SCALE_DOWN_4X, SCALE_DOWN_8X};
    bool hardDecSupport = false;
    for (auto &scale : vecScale) {
      imgDecParam.scale = scale;
      CHECK_ERR(
          lynImageGetInfo(&imgDecParam, &m_decImgInfo, &hardDecSupport));
      if ((m_decImgInfo.output.height <= 1080) &&
          (m_decImgInfo.output.width <= 1920)) {
        break;
      }
    }
    if (enableHwDec && hardDecSupport) m_useHwDec = true;
  }

  void GetImageDecInfo(lynImageInfo_t *outInfo) { *outInfo = m_decImgInfo; }

  bool DecodeImageToDevice(lynStream_t stream, uint8_t *deviceOutMem) {
    // todo
    std::ifstream imageFile(m_imagePath, std::ifstream::binary);
    if (imageFile.is_open() != true) {
      std::cout << __FILE__ << ":" << __LINE__ << " " << m_imagePath
                << " file is not opened" << std::endl;
      return false;
    }
    imageFile.seekg(0, imageFile.end);
    uint32_t imageSize = imageFile.tellg();
    imageFile.seekg(0, imageFile.beg);
    uint8_t *imageData = new uint8_t[imageSize];
    if (nullptr != imageData) {
      imageFile.read((char *)(imageData), imageSize);
    }

    lynImageDecAttr_t decAttr;
    decAttr.inBuf.size = imageSize;
    decAttr.outBuf.size = m_decImgInfo.output.predictBufSize;
    decAttr.info = m_decImgInfo;

    // 判断是否硬解码
    if (m_useHwDec) {
      // 申请设备侧的内存
      CHECK_ERR(lynMalloc((void **)&decAttr.inBuf.data, decAttr.inBuf.size));
      decAttr.outBuf.data = deviceOutMem;
      // 将图片拷贝到设备端内存
      lynMemcpy(decAttr.inBuf.data, imageData, imageSize, ClientToServer);
      lynJpegDecodeAsync(stream, &decAttr);
      lynSynchronizeStream(stream);
      lynFree((void *)decAttr.inBuf.data);
    } else {
      decAttr.inBuf.data = (uint8_t *)imageData;
      decAttr.outBuf.data = new uint8_t[decAttr.outBuf.size];
      CHECK_ERR(lynImageDecodeSoft(&decAttr));
      // 将解码拷贝到设备端内存
      lynMemcpy(deviceOutMem, decAttr.outBuf.data, decAttr.outBuf.size,
                ClientToServer);
      delete[] decAttr.outBuf.data;
    }
    delete[] imageData;
    return true;
  }

 private:
  lynImageInfo_t m_decImgInfo;
  std::string m_imagePath;
  bool m_useHwDec = false;
};